package com.example.shop.fgo.task.upload.controller;

import android.os.SystemClock;

import com.example.shop.fgo.Constant;
import com.example.shop.fgo.entity.UploadCheckEntity;
import com.example.shop.fgo.net.UploadCheckServe;
import com.example.shop.fgo.task.common.controller.TaskMsg;
import com.example.shop.fgo.task.common.controller.UpdatePart;
import com.example.shop.fgo.task.common.model.TaskState;
import com.example.shop.fgo.task.upload.model.UploadTask;
import com.example.shop.fgo.utils.CookieUtil;
import com.example.shop.fgo.utils.SizeUtil;
import com.example.shop.library.net.NetJsonUtil;
import com.orhanobut.logger.Logger;

import org.greenrobot.eventbus.EventBus;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import retrofit2.Call;
import retrofit2.Response;

/**
 * Created by Administrator on 2017/2/20.
 */

public class UploadThread extends Thread {
    private UploadTask mUploadTaskNow;
    private UploadController mUploadController;
    private static final  Object SYNC=new Object();
    private static final String BOUNDARY="----------hehedadaxxxxoooo";
    private static final String BREAK="\r\n";

    public UploadThread() {
        mUploadController = new UploadController();
    }

    @Override
    public void run() {
        super.run();

         while (true) {

            synchronized (SYNC) {
                mUploadTaskNow = mUploadController.getUploadTaskWait();

                //没有下载任务了，那么线程就终止了。。
                if (mUploadTaskNow == null) {
                    Logger.e("全部上传完毕  ");
                    break;
                }
                mUploadController.updateUploadTaskState(mUploadTaskNow, TaskState.TASK_STATE_PREPARE);
                Logger.e("找到排队任务 ：  " + mUploadTaskNow.getName());
            }

            boolean isPrepareOk = doPrepare();
            //如果当前任务准备失败了，那么我们就继续下一个任务
            if (!isPrepareOk) {
                continue;
            }
            Logger.e("准备成功 ：  " + mUploadTaskNow.getName());
            mUploadController.updateUploadTaskState(mUploadTaskNow, TaskState.TASK_STATE_ING);
            if (mUploadTaskNow.type == UploadTask.TYPE_DA) {
                //断点续传大文件
                断点续传大文件();
            } else {
                //小文件用普通上传
                普通上传();
            }
        }
    }
    private void 普通上传() {
        HttpURLConnection httpURLConnection=null;
        OutputStream fileOutputStream=null;
        FileInputStream inputStream=null;
        try {
            URL url=new URL(mUploadTaskNow.getUrl());
            httpURLConnection = (HttpURLConnection) url.openConnection();

            httpURLConnection.setRequestMethod("POST");
            httpURLConnection.setDoInput(true);
            httpURLConnection.setDoOutput(true);
//                httpURLConnection.setRequestProperty("Content-Length", mUploadTaskNow.getTotalSize()+"");


            httpURLConnection.setRequestProperty("Cookie", CookieUtil.getCookie());
            httpURLConnection.setRequestProperty("Content-Type", "multipart/form-data; boundary="+BOUNDARY);
            httpURLConnection.setRequestProperty("Connection", "keep-alive");

            fileOutputStream=httpURLConnection.getOutputStream();

            StringBuilder stringBuilder=new StringBuilder();
            //aid  1        pid  0    name xxx.txt       Filedata  xxx.txt  ..............

            stringBuilder.append(BOUNDARY);
            stringBuilder.append(BREAK);
            stringBuilder.append("Content-Disposition: form-data; name=\"aid\"");
            stringBuilder.append(BREAK);
            stringBuilder.append(BREAK);
            stringBuilder.append("1");
            stringBuilder.append(BREAK);

            stringBuilder.append(BOUNDARY);
            stringBuilder.append(BREAK);
            stringBuilder.append("Content-Disposition: form-data; name=\"pid\"");
            stringBuilder.append(BREAK);
            stringBuilder.append(BREAK);
            stringBuilder.append(mUploadTaskNow.getPid());
            stringBuilder.append(BREAK);

            stringBuilder.append(BOUNDARY);
            stringBuilder.append(BREAK);
            stringBuilder.append("Content-Disposition: form-data; name=\"name\"");
            stringBuilder.append(BREAK);
            stringBuilder.append(BREAK);
            stringBuilder.append(mUploadTaskNow.getName());
            stringBuilder.append(BREAK);

            stringBuilder.append(BOUNDARY);
            stringBuilder.append(BREAK);
            stringBuilder.append("Content-Disposition: form-data; name=\"Filedata\"; filename=\""+mUploadTaskNow.getName()+"\"");//filename="文件名称"
            stringBuilder.append(BREAK);
            stringBuilder.append("Content-Type: text/plain");
            stringBuilder.append(BREAK);
            stringBuilder.append(BREAK);

            fileOutputStream.write(stringBuilder.toString().getBytes());

            inputStream=new FileInputStream(mUploadTaskNow.getFilePath());
            byte[] bs = new byte[1024 * 100];
            int total = -1;
            while ((total = inputStream.read(bs)) != -1) {
                Logger.e("上传了： "+total);
                //取消任务
                if (mUploadController.hasCanceled(mUploadTaskNow)) {
//                      如果当前任务取消了，  终止当前任务的执行，开始下一个任务
                    return;
                }

                //暂停任务
                if (mUploadController.haspaused(mUploadTaskNow)) {
                    return;
                }

                fileOutputStream.write(bs, 0, total);

            }
            fileOutputStream.write(BREAK.getBytes());
            fileOutputStream.write((BOUNDARY+"--").getBytes());

            //基于httpUrlconnetion的这个类的特殊性，不读就不写
            //httpURLConnection.getOutputStream();获取指向服务器的输出流，然后
            //fileOutputStream.write( 写数据到服务器 ，其内部操作原理是这样的：
            //当我们调用了write(方法时，并不会马上把数据写到服务器，有一个类似缓冲区的东西在我们内存里
            //所以我们的数据会先write到缓冲区当中，等待我们read的时候再写到网络上
            httpURLConnection.getInputStream().read();

            mUploadController.updateUploadTaskState(mUploadTaskNow, TaskState.TASK_STATE_DONE);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            release(inputStream, fileOutputStream, httpURLConnection);
        }

    }

    private boolean doPrepare() {
        final boolean[] isPrepareOK = {false};

        //查找文件是否已经存在，如果存在，询问是否覆盖
        UploadCheckServe uploadCheckServe = NetJsonUtil.getRetrofit(Constant.BASE_URL, UploadCheckServe.class);
        Call<UploadCheckEntity> call = uploadCheckServe.check(mUploadTaskNow.pid, mUploadTaskNow.getName(), CookieUtil.getCookie());

        try {
            Response<UploadCheckEntity> response = call.execute();

            UploadCheckEntity uploadCheckEntity = response.body();
            Logger.e("uploadCheckEntity.isState()  "+uploadCheckEntity.isState());
            if (uploadCheckEntity.isState()) {

                final TaskMsg taskMsg = TaskMsg.obtain();
                taskMsg.mTask=mUploadTaskNow;
                taskMsg.exists=true;
                taskMsg.mUpdatePart= UpdatePart.EXISTS;
                EventBus.getDefault().post(taskMsg);

                while (true){
                    SystemClock.sleep(1000);
                    //看看用户决定没有
                    if (mUploadTaskNow.decision!=UploadTask.NOT_YET){
                        if (mUploadTaskNow.decision==UploadTask.FG){
                            isPrepareOK[0] =true;
                        }else if (mUploadTaskNow.decision==UploadTask.BUFG){
                            isPrepareOK[0] =false;
                        }
                        break;
                    }

                }
            }else {
                final TaskMsg taskMsg = TaskMsg.obtain();
                taskMsg.mTask=mUploadTaskNow;
                taskMsg.exists=false;
                taskMsg.mUpdatePart= UpdatePart.EXISTS;
                EventBus.getDefault().post(taskMsg);

                isPrepareOK[0] =true;
            }
        } catch (IOException e) {
            e.printStackTrace();
            mUploadController.updateUploadTaskState(mUploadTaskNow, TaskState.TASK_STATE_ERROR_SERVER);
            isPrepareOK[0] =false;
        }

        return isPrepareOK[0] ;
    }


    public void release(InputStream inputStream, OutputStream fileOutputStream, HttpURLConnection httpURLConnection) {
        if (inputStream != null) {
            try {
                inputStream.close();
                inputStream = null;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        if (fileOutputStream != null) {
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                    fileOutputStream = null;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        if (httpURLConnection != null) {
            httpURLConnection.disconnect();
            httpURLConnection = null;
        }

    }




    private void 断点续传大文件() {
        while (true) {


            long timeBegin = System.currentTimeMillis();
            int total = 0;
            HttpURLConnection httpURLConnection = null;
            OutputStream fileOutputStream = null;
            FileInputStream inputStream = null;
            try {
                URL url = new URL(mUploadTaskNow.getUrl());
                httpURLConnection = (HttpURLConnection) url.openConnection();

                httpURLConnection.setRequestMethod("POST");
                httpURLConnection.setDoInput(true);
                httpURLConnection.setDoOutput(true);
//                httpURLConnection.setRequestProperty("Content-Length", mUploadTaskNow.getTotalSize()+"");


                httpURLConnection.setRequestProperty("Cookie", CookieUtil.getCookie());
                httpURLConnection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
                httpURLConnection.setRequestProperty("Connection", "keep-alive");

                fileOutputStream = httpURLConnection.getOutputStream();

                StringBuilder stringBuilder = new StringBuilder();
                //aid  1        pid  0    name xxx.txt       Filedata  xxx.txt  ..............

                stringBuilder.append(BOUNDARY);
                stringBuilder.append(BREAK);
                stringBuilder.append("Content-Disposition: form-data; name=\"aid\"");
                stringBuilder.append(BREAK);
                stringBuilder.append(BREAK);
                stringBuilder.append("1");
                stringBuilder.append(BREAK);

                stringBuilder.append(BOUNDARY);
                stringBuilder.append(BREAK);
                stringBuilder.append("Content-Disposition: form-data; name=\"pid\"");
                stringBuilder.append(BREAK);
                stringBuilder.append(BREAK);
                stringBuilder.append(mUploadTaskNow.getPid());
                stringBuilder.append(BREAK);

                stringBuilder.append(BOUNDARY);
                stringBuilder.append(BREAK);
                stringBuilder.append("Content-Disposition: form-data; name=\"name\"");
                stringBuilder.append(BREAK);
                stringBuilder.append(BREAK);
                stringBuilder.append(mUploadTaskNow.getName());
                stringBuilder.append(BREAK);

                stringBuilder.append(BOUNDARY);
                stringBuilder.append(BREAK);
                stringBuilder.append("Content-Disposition: form-data; name=\"Filedata\"; filename=\"" + mUploadTaskNow.getName() + "\"");//filename="文件名称"
                stringBuilder.append(BREAK);
                stringBuilder.append("Content-Type: text/plain");
                stringBuilder.append(BREAK);
                stringBuilder.append(BREAK);

                fileOutputStream.write(stringBuilder.toString().getBytes());

                inputStream = new FileInputStream(mUploadTaskNow.getFilePath());

//            RandomAccessFile randomAccessFile=new RandomAccessFile();

                //这句很关键
                inputStream.skip(mUploadTaskNow.getNowSize());


                byte[] bs = new byte[1024 * 50];
                int temp = -1;

                while ((temp = inputStream.read()) != -1) {


                    if (total >= 1024 * 50) {
                        break;
                    }
                    bs[total++] = (byte) temp;

                }


                fileOutputStream.write(bs, 0, total);
                fileOutputStream.write(BREAK.getBytes());
                fileOutputStream.write((BOUNDARY + "--").getBytes());

                //基于httpUrlconnetion的这个类的特殊性，不读就不写
                //httpURLConnection.getOutputStream();获取指向服务器的输出流，然后
                //fileOutputStream.write( 写数据到服务器 ，其内部操作原理是这样的：
                //当我们调用了write(方法时，并不会马上把数据写到服务器，有一个类似缓冲区的东西在我们内存里
                //所以我们的数据会先write到缓冲区当中，等待我们read的时候再写到网络上
                httpURLConnection.getInputStream().read();

                mUploadController.updateUploadTaskSize(mUploadTaskNow, total);


            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                release(inputStream, fileOutputStream, httpURLConnection);
                if (mUploadTaskNow.getNowSize() >= mUploadTaskNow.getTotalSize()) {
                    Logger.e(mUploadTaskNow.getName() + "上传完毕！！！");
                    mUploadController.updateUploadTaskState(mUploadTaskNow, TaskState.TASK_STATE_DONE);
                    return;
                }
                //取消任务
                if (mUploadController.hasCanceled(mUploadTaskNow)) {
//             如果当前任务取消了，  终止当前任务的执行，开始下一个任务
                    return;
                }

                //暂停任务
                if (mUploadController.haspaused(mUploadTaskNow)) {
                    return;
                }

                long timeEnd = System.currentTimeMillis();

                float timePast = (timeEnd - timeBegin) / 1000.0f;

                long speedBytes = (long) (total / timePast);

                String speed = SizeUtil.formatSpeed(speedBytes);
                mUploadController.updateUploadTaskSpeed(mUploadTaskNow, speed);


            }
        }
    }
}
